#pragma once

#include "interfaces.h"
#include "SceneNodes.h"
#include "Geometry.h"
#include "RandomEngine.h"


class RootSceneNode : public ISceneNode 
{
public:
	RootSceneNode()  {};
	~RootSceneNode() {
	};

private:
	virtual bool VPostRender(IScene * pScene) { assert("Attempt to call Root Scene Node forbidden function."); return false; };
	virtual bool VPreRender(IScene * pScene) { assert("Attempt to call Root Scene Node forbidden function."); return false; };
public:
	SceneNodeList m_Children;
	virtual SceneNodeList& VGetChildren() { return m_Children; };
	virtual bool VOnRender(IScene * pScene) { return VRenderChildren(pScene); };
	virtual bool VRenderChildren(IScene *pScene)
	{
		SceneNodeList::iterator begin = m_Children.begin();
		SceneNodeList::iterator end = m_Children.end();
		while(begin != end)
		{
			if((*begin)->VPreRender(pScene))
			{
				(*begin)->VOnRender(pScene);
				(*begin)->VPostRender(pScene);
			}
			begin++;
		}
		return true;
	};
	virtual bool VAddChild(SceneNodePtr scene_node)
	{
		//(TODO :check if it is valid and) add it
		m_Children.push_back(scene_node);
		return true;
	};
	virtual bool VOnUpdate(float fTime) { 
		SceneNodeList::iterator begin = m_Children.begin();
		SceneNodeList::iterator end = m_Children.end();
		while(begin != end)
		{
			if(!(*begin)->VOnUpdate(fTime))
			{
				return false;
			}
			begin++;
		}
		return true;
	};
	virtual bool VIsVisible() { return true; };
	virtual ActorId VGetId() { return 0; };
};

class Scene : public IScene, public IScreenElement
{
public:
	Scene();
	~Scene() {
	//Release the matrix stack
		if(m_MatrixStack != NULL)
		{
			m_MatrixStack->Release();
		}
	
	};

	virtual bool VOnRender();
	virtual bool VOnUpdate(float fTime);
	void VBuildAndSetViewMatrix(const Vec3 & Position = Vec3(0,0,0), const Vec3 & LookAt = Vec3(1,0,1), const Vec3 & WorldUpVector = Vec3(0,1,0));
	void VBuildAndSetProjMatrix(float FOV = D3DX_PI / 4, float AspectRatio = 1.0f, float ClippingPlane_near = 1.0f, float ClippingPlane_far = 100.0f);
	void VPushAndSetMatrix(const Mat4x4 & ToWorld);
	void VPopMatrix();
	virtual SceneNodePtr VGetRootSceneNode() { return m_RootSceneNode; };
	ISceneNode* VGetNodeById(const ActorId id);
	virtual void VAddSceneNode(const SceneNodePtr node);

	SceneNodePtr m_Camera; // pointer to the active camera somewhere in the RootSceneNode; 
	SceneNodePtr m_RootSceneNode;
	SceneNodeMap m_scenenodes;
	ID3DXMatrixStack *m_MatrixStack;
};